package com.atguigu.gmall.list.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.list.mapper.GoodsRepsitory;
import com.atguigu.gmall.list.service.SearchService;
import com.atguigu.gmall.model.list.*;
import com.atguigu.gmall.model.product.BaseAttrInfo;
import com.atguigu.gmall.model.product.BaseCategoryView;
import com.atguigu.gmall.model.product.BaseTrademark;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;

import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;

import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;


@Service
public  class SearchServiceImpl implements SearchService {

    @Autowired
    ProductFeignClient productFeignClient;

    @Autowired
    GoodsRepsitory goodsRepsitory;

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Override
    public void upperGoods(Long skuId) {
        Goods goods = new Goods();

        SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
        goods.setId(skuId);
        goods.setTitle(skuInfo.getSkuName());
        goods.setDefaultImg(skuInfo.getSkuDefaultImg());
        goods.setPrice(productFeignClient.getSkuPrice(skuId).doubleValue());
        goods.setCreateTime(new Date());

        //赋值品牌数据
        BaseTrademark trademark = productFeignClient.getTrademark(skuInfo.getTmId());
        goods.setTmId(trademark.getId());
        goods.setTmName(trademark.getTmName());
        goods.setTmLogoUrl(trademark.getLogoUrl());

        //赋值分类数据
        BaseCategoryView categoryView = productFeignClient.getCategoryView(skuInfo.getCategory3Id());
        goods.setCategory1Id(categoryView.getCategory1Id());
        goods.setCategory2Id(categoryView.getCategory2Id());
        goods.setCategory3Id(categoryView.getCategory3Id());

        goods.setCategory1Name(categoryView.getCategory1Name());
        goods.setCategory2Name(categoryView.getCategory2Name());
        goods.setCategory3Name(categoryView.getCategory3Name());

        //赋值平台属性平台属性值
        List<BaseAttrInfo> attrList = this.productFeignClient.getAttrList(skuId);
        List<SearchAttr> attrListCollect = attrList.stream().map(baseAttrInfo -> {
            SearchAttr searchAttr = new SearchAttr();
            searchAttr.setAttrId(baseAttrInfo.getId());
            searchAttr.setAttrName(baseAttrInfo.getAttrName());
            searchAttr.setAttrValue(baseAttrInfo.getAttrValueList().get(0).getValueName());

            return searchAttr;
        }).collect(Collectors.toList());

        goods.setAttrs(attrListCollect);
        goodsRepsitory.save(goods);
    }

    @Override
    public void lowerGoods(Long skuId) {
        this.goodsRepsitory.deleteById(skuId);
    }

    @Override
    public void incrHotScore(Long skuId) {
        String hotKey = "hotScore";
        Double count = this.redisTemplate.opsForZSet().incrementScore(hotKey, "skuId:" + skuId, 1);

        if(count%10==0){
            //跟新es
            Optional<Goods> optional = this.goodsRepsitory.findById(skuId);
            Goods goods = optional.get();
            goods.setHotScore(count.longValue());
            //跟新之后放入es
            this.goodsRepsitory.save(goods);
        }
    }

    @Override
    public SearchResponseVo search(SearchParam searchParam) throws Exception{
        SearchResponseVo searchResponseVo = new SearchResponseVo();

        //准备好dsl语句
        SearchRequest searchRequest = this.buildQueryDsl(searchParam);
        //执行dsl语句
        SearchResponse searchResponse = this.restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

       /* private List<SearchResponseTmVo> trademarkList;
        //所有商品的顶头显示的筛选属性
        private List<SearchResponseAttrVo> attrsList = new ArrayList<>();
        //检索出来的商品信息
        private List<Goods> goodsList = new ArrayList<>();
        private Long total;//总记录数
        private Integer pageSize;//每页显示的内容
        private Integer pageNo;//当前页面
        private Long totalPages;*/

       searchResponseVo = this.parseSearchResult(searchResponse);

       searchResponseVo.setPageNo(searchParam.getPageNo());
       searchResponseVo.setPageSize(searchParam.getPageSize());
       Long totalPages = (searchResponseVo.getTotal()+searchParam.getPageSize()-1)/searchParam.getPageSize();
       searchResponseVo.setTotalPages(totalPages);
       return searchResponseVo;
    }

    private SearchResponseVo parseSearchResult(SearchResponse searchResponse) {
        SearchResponseVo searchResponseVo = new SearchResponseVo();

        SearchHits hits = searchResponse.getHits();
        searchResponseVo.setTotal(hits.getTotalHits().value);

        //赋值商品列表
        List<Goods> goodsList = new ArrayList<>();
        //获取到subHits数据
        SearchHit[] subHits = hits.getHits();
        if(subHits != null && subHits.length>0){
            for (SearchHit subHit : subHits) {
                String sourceAsString = subHit.getSourceAsString();
                Goods goods = JSON.parseObject(sourceAsString, Goods.class);
                if(subHit.getHighlightFields().get("title") != null){
                    Text title = subHit.getHighlightFields().get("title").getFragments()[0];
                    goods.setTitle(title.toString());
                }
                goodsList.add(goods);
            }
        }
        //商品集合赋值完成
        searchResponseVo.setGoodsList(goodsList);
        List<SearchResponseTmVo> trademarkList = new ArrayList<>();
        //获取聚合中对应的品牌数据
        Map<String, Aggregation> aggregationMap = searchResponse.getAggregations().asMap();
        //获取品牌Id聚合对象
        ParsedLongTerms tmIdAgg = (ParsedLongTerms) aggregationMap.get("tmIdAgg");
        //赋值品牌数据
        trademarkList = tmIdAgg.getBuckets().stream().map(bucket -> {
            //创建品牌对象
            SearchResponseTmVo searchResponseTmVo = new SearchResponseTmVo();
            String keyAsString = ((Terms.Bucket) bucket).getKeyAsString();
            searchResponseTmVo.setTmId(Long.parseLong(keyAsString));

            //获取品牌名称
            ParsedStringTerms tmNameAgg = ((Terms.Bucket) bucket).getAggregations().get("tmNameAgg");
            String tmName = tmNameAgg.getBuckets().get(0).getKeyAsString();
            searchResponseTmVo.setTmName(tmName);

            //获取品牌URl
            ParsedStringTerms tmLogoUrlAgg = ((Terms.Bucket) bucket).getAggregations().get("tmLogoUrlAgg");
            String tmLogoUrl = tmLogoUrlAgg.getBuckets().get(0).getKeyAsString();
            searchResponseTmVo.setTmLogoUrl(tmLogoUrl);

            return searchResponseTmVo;
        }).collect(Collectors.toList());
        searchResponseVo.setTrademarkList(trademarkList);

        ParsedNested attrAgg = (ParsedNested) aggregationMap.get("attrAgg");
        ParsedLongTerms attrIdAgg = attrAgg.getAggregations().get("attrIdAgg");
        List<SearchResponseAttrVo> attrsList = attrIdAgg.getBuckets().stream().map(bucker -> {
            //创建对象
            SearchResponseAttrVo searchResponseAttrVo = new SearchResponseAttrVo();
            String keyAsString = ((Terms.Bucket) bucker).getKeyAsString();
            searchResponseAttrVo.setAttrId(Long.parseLong(keyAsString));
            //赋值平台属性
            ParsedStringTerms attrNameAgg = ((Terms.Bucket) bucker).getAggregations().get("attrNameAgg");
            String attrName = attrNameAgg.getBuckets().get(0).getKeyAsString();
            searchResponseAttrVo.setAttrName(attrName);
            //赋值品牌性值名
            ParsedStringTerms attrValueAgg = ((Terms.Bucket) bucker).getAggregations().get("attrValueAgg");
            List<String> attrValueList = attrValueAgg.getBuckets().stream().map(Terms.Bucket::getKeyAsString).collect(Collectors.toList());

            searchResponseAttrVo.setAttrValueList(attrValueList);

            return searchResponseAttrVo;

        }).collect(Collectors.toList());

        searchResponseVo.setAttrsList(attrsList);

        return searchResponseVo;
    }

    private SearchRequest buildQueryDsl(SearchParam searchParam) {
        //声明一个查询器
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //声明一个BoolQueryBuilder
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //判断用户是否根据Id过滤
        if(!StringUtils.isEmpty(searchParam.getCategory1Id())){
            boolQueryBuilder.filter(QueryBuilders.termQuery("category1Id",searchParam.getCategory1Id()));
        }
        if(!StringUtils.isEmpty(searchParam.getCategory2Id())){
            boolQueryBuilder.filter(QueryBuilders.termQuery("category2Id",searchParam.getCategory2Id()));
        }
        if(!StringUtils.isEmpty(searchParam.getCategory3Id())){
            boolQueryBuilder.filter(QueryBuilders.termQuery("category3Id",searchParam.getCategory3Id()));
        }
        //判断是否根据关键字索引
        if(!StringUtils.isEmpty(searchParam.getKeyword())){
            MatchQueryBuilder title = QueryBuilders.matchQuery("title",searchParam.getKeyword()).operator(Operator.AND);
            //过滤检索同时拥有
            boolQueryBuilder.must(title);
            //高亮
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.field("title");
            highlightBuilder.preTags("<span stylescolor:red>");
            highlightBuilder.postTags("</span>");
            searchSourceBuilder.highlighter(highlightBuilder);
        }

        //根据平拍id进行过滤
        String trademark = searchParam.getTrademark();
        if(!StringUtils.isEmpty(trademark)){
            String[] split = trademark.split(":");
            if (split != null && split.length==2){
                boolQueryBuilder.filter(QueryBuilders.termQuery("tmId",split[0]));
            }
        }
        //根据平台属性值过滤
        String[] props = searchParam.getProps();
        if(props != null && props.length>0){
            for (String prop : props) {
                String[] split = prop.split(":");
                if(split != null && split.length == 3){
                    //创建boolQuery
                    BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
                    BoolQueryBuilder subBoolQuery = QueryBuilders.boolQuery();
                    subBoolQuery.must(QueryBuilders.termQuery("attrs.attrId",split[0]));
                    subBoolQuery.must(QueryBuilders.termQuery("attrs.attrValue",split[1]));
                    boolQuery.must(QueryBuilders.nestedQuery("attrs",subBoolQuery, ScoreMode.None));

                    boolQueryBuilder.filter(boolQuery);
                }
            }
        }

        searchSourceBuilder.query(boolQueryBuilder);
        //分页
        searchSourceBuilder.query(boolQueryBuilder);
        //构建分页
        int from = (searchParam.getPageNo()-1)*searchParam.getPageSize();
        searchSourceBuilder.from(from);
        searchSourceBuilder.size(searchParam.getPageSize());
        //排序
        String order = searchParam.getOrder();
        if(!StringUtils.isEmpty(order)){
            //判断排序规则
            String[] split = order.split(":");
            if(split != null && split.length == 2){
                String field = null;
                switch (split[0]){
                    case "1":
                        field="hotScore";
                        break;
                    case "2":
                        field="price";
                        break;
                }
                searchSourceBuilder.sort(field,"asc".equals(split[1])? SortOrder.ASC:SortOrder.DESC);
            }else {
                searchSourceBuilder.sort("hotScore",SortOrder.DESC);
            }
        }

        //聚合品牌
        searchSourceBuilder.aggregation(AggregationBuilders.terms("tmIdAgg").field("tmId").
                subAggregation(AggregationBuilders.terms("tmNameAgg").field("tmName")).
                subAggregation(AggregationBuilders.terms("tmLogoUrlAgg").field("tmLogoUrl")));

        //平台属性聚合
        searchSourceBuilder.aggregation(AggregationBuilders.nested("attrAgg","attrs").
                subAggregation(AggregationBuilders.terms("attrIdAgg").field("attrs.attrId").
                        subAggregation(AggregationBuilders.terms("attrNameAgg").field("attrs.attrName")).
                        subAggregation(AggregationBuilders.terms("attrValueAgg").field("attrs.attrValue"))));

        //设置索引库
        SearchRequest searchRequest = new SearchRequest("goods");
        searchRequest.source(searchSourceBuilder);
        searchSourceBuilder.fetchSource(new String[]{"id","defaultImg","title","price","creamTime"},null);
        System.out.println("DSL:\t" + searchSourceBuilder.toString());

        return searchRequest;


    }


}
